#coding=utf-8

import wx
import wx.grid as grid
import math

class TableDays(grid.PyGridTableBase):
    days = []
    date = wx.DateTime.Now()
    rowLabels = []
    def __init__(self):
        grid.PyGridTableBase.__init__(self)
        self.colLabels = [wx.GetTranslation('Su'), wx.GetTranslation('Mo'),
                          wx.GetTranslation('Tu'), wx.GetTranslation('We'),
                          wx.GetTranslation('Th'), wx.GetTranslation('Fr'),
                          wx.GetTranslation('Sa')]

    def GetNumberRows(self):
        return 6

    def GetNumberCols(self):
        return 7

    def GetColLabelValue(self, col):
        return self.colLabels[col]

    def GetRowLabelValue(self, row):
        if len(self.rowLabels) == 6:
            return self.rowLabels[row]
        return '0'

    def GetValue(self, row, col):
        if len(self.days) == 42:
            return self.days[row*7+col].GetDay()
        return '0'
    
    def UpdateWeeks(self):
        self.rowLabels = []
        week = self.days[0].GetWeekOfYear(wx.DateTime.Sunday_First)
        for i in range(0, 6):
            self.rowLabels.append(str(week))
            week += 1

class GridDays(grid.Grid):
    beginRangeSelect = False
    beginRangeRow = 0
    beginRangeCol = 0
    endRangeRow = 0
    endRangeCol = 0
    rangeCells = []

    
    def __init__(self, parent):
        grid.Grid.__init__(self, parent, -1)
        self.SetDefaultColSize(26)
        self.SetDefaultRowSize(18)
        self.SetRowLabelSize(26)
        self.SetColLabelSize(18)
        self.EnableDragCell(False)
        self.EnableDragColMove(False)
        self.EnableDragGridSize(False)
        self.EnableDragRowSize(False)
        self.EnableDragColSize(False)
        self.EnableEditing(False)
        self.SetGridLineColour(wx.Color(225, 225, 225))
        
        self.SetMargins(-20, 0)
        self.AutoSizeColumns(False)
        
        self.SetDefaultCellAlignment(wx.ALIGN_CENTER, wx.ALIGN_CENTER)
        self.SetSelectionBackground(self.GetDefaultCellBackgroundColour())
        self.SetSelectionForeground(self.GetDefaultCellTextColour())

    def SelectRange(self):
        self.ClearRange()
        if (self.beginRangeRow * 7 + self.beginRangeCol) < (self.endRangeRow * 7 + self.endRangeCol):
            step = 1
        else:
            step = -1
        r, c = self.beginRangeRow, self.beginRangeCol
        self.BeginBatch()
        while (r * 7 + c) * step <= (self.endRangeRow * 7 + self.endRangeCol) * step:
            self.SelectCell([r, c])
            self.rangeCells.append([r, c])
            c += step
            if c > 6:
                r += 1
                c = 0
            elif c < 0:
                r -= 1
                c = 6
        self.EndBatch()
    
    def UnSelectCell(self, cell):
        if self.GetCellTextColour(cell[0], cell[1]) == wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT):        
            self.SetCellTextColour(cell[0], cell[1], self.GetDefaultCellTextColour())
        self.SetCellBackgroundColour(cell[0], cell[1], self.GetDefaultCellBackgroundColour())

    def SelectCell(self, cell):
        if self.GetCellTextColour(cell[0], cell[1]) == self.GetDefaultCellTextColour():
            self.SetCellTextColour(cell[0], cell[1], wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
        self.SetCellBackgroundColour(cell[0], cell[1], wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
        
    def ClearRange(self):
        self.BeginBatch()
        for cell in self.rangeCells:
            self.UnSelectCell(cell)
        self.rangeCells = []
        self.EndBatch()
        

class PanelCalendar(wx.Panel):
    idShowDetails = wx.NewId()
    
    def __init__(self, parent, id = -1, 
            pos = wx.DefaultPosition, date = wx.DateTime.Now()):
        wx.Panel.__init__(self, parent, id, pos, (208, 145))
        
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        
        self.sizerCaption = wx.BoxSizer(wx.HORIZONTAL)
        
        buttonLastYear = wx.StaticText(self, -1, '<<', size = (30, 20),
            style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE)
        buttonNextYear = wx.StaticText(self, -1, '>>', size = (30, 20),
            style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE)
        buttonLastMonth = wx.StaticText(self, -1, '<')
        buttonNextMonth = wx.StaticText(self, -1, '>')
        
        self.title = wx.StaticText(
            self, -1, '', style = wx.ALIGN_CENTRE | wx.ST_NO_AUTORESIZE)
        
        self.sizerCaption.Add(buttonLastYear)
        self.sizerCaption.Add(buttonLastMonth)
        self.sizerCaption.Add(self.title, 1, wx.ALL, 0)
        self.sizerCaption.Add(buttonNextMonth)
        self.sizerCaption.Add(buttonNextYear)
        
#        self.SetSizeHints(200, -1)
        
        buttonLastYear.Bind(wx.EVT_LEFT_UP, self.OnLastYear)
        buttonNextYear.Bind(wx.EVT_LEFT_UP, self.OnNextYear)
        buttonLastMonth.Bind(wx.EVT_LEFT_UP, self.OnLastMonth)
        buttonNextMonth.Bind(wx.EVT_LEFT_UP, self.OnNextMonth)
        
        buttonLastYear.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
        buttonNextYear.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
        buttonLastMonth.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
        buttonNextMonth.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
        
        buttonLastYear.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        buttonNextYear.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        buttonLastMonth.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        buttonNextMonth.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)

        
#        sizerWeekdays = wx.BoxSizer(wx.HORIZONTAL)
#        for i in range(0, 7):
#            weekday = wx.StaticText(self, -1, self.weekdays[i], size = (-1, 20),
#                style = wx.ALIGN_CENTRE | wx.ST_NO_AUTORESIZE)
#            sizerWeekdays.Add(weekday, 1, wx.ALL | wx.EXPAND, 0)
        
        self.date = date
        self.daystable = TableDays()
        self.days = GridDays(self)
        self.days.SetSize((-1, 104))
        self.days.SetTable(self.daystable)
        self.SetDate()

        
        self.sizer.Add(self.sizerCaption, 0, wx.EXPAND, 2)
#        self.sizer.Add(sizerWeekdays, 0, wx.EXPAND, 2)
#        self.sizer.Add(wx.StaticLine(self, size = (2, 1)), 0, wx.EXPAND, 1)
        self.sizer.Add(self.days, 0, wx.EXPAND, 2)
        
        self.SetSizer(self.sizer)
        self.Layout()
        
        self.days.Bind(grid.EVT_GRID_CELL_LEFT_CLICK, self.OnLeftClickDay)
#        self.days.Bind(grid.EVT_GRID_SELECT_CELL, self.OnSelectDays)

        gridwindow = wx.FindWindowByName('grid window', self.days)

        gridwindow.Bind(wx.EVT_LEFT_DOWN, self.OnDaysLeftDown)
        gridwindow.Bind(wx.EVT_MOTION, self.OnDaysMouseMove)
        gridwindow.Bind(wx.EVT_LEFT_UP, self.OnDaysLeftUp)
        gridwindow.Bind(wx.EVT_LEAVE_WINDOW, self.OnDaysLeftUp)
        
#=================================================

    def OnLastYear(self, event):
        self.GotoLastYear()
        
    def OnNextYear(self, event):
        self.GotoNextYear()
    
    def OnLastMonth(self, event):
        self.GotoLastMonth()
        
    def OnNextMonth(self, event):
        self.GotoNextMonth()
        
    def GotoLastYear(self):
        self.date += wx.DateSpan_Years(-1)
        self.SetDate()
        
    def GotoNextYear(self):
        self.date += wx.DateSpan_Year()
        self.SetDate()
    
    def GotoLastMonth(self):
        self.date += wx.DateSpan_Months(-1)
        self.SetDate()
        
    def GotoNextMonth(self):
        self.date += wx.DateSpan_Month()
        self.SetDate()
        
#=================================================
    def OnLeftClickDay(self, event):
        i = event.GetRow() * 7 + event.GetCol()
        date = self.daystable.days[i]
        if date.GetMonth() != self.date.GetMonth():
            self.date = date
            self.SetDate()
        else:
            self.date = date
            self.currentCell = i
            event.Skip()
        self.days.ClearRange()

    def OnDaysLeftDown(self, event):
        self.days.beginRangeSelect = True
        self.days.beginRangeRow = self.days.YToRow(event.GetY())
        self.days.beginRangeCol = self.days.XToCol(event.GetX())
        event.Skip()

    def OnDaysLeftUp(self, event):
        if self.days.beginRangeSelect:
            self.days.beginRangeSelect = False
            self.ShowDetails()

    def OnDaysMouseMove(self, event):
        if self.days.beginRangeSelect:
            r = self.days.YToRow(event.GetY())
            c = self.days.XToCol(event.GetX())
            if (r != self.days.beginRangeRow 
                or c != self.days.beginRangeCol) and (r != self.days.endRangeRow or c != self.days.endRangeCol):
                self.days.endRangeRow, self.days.endRangeCol = r, c
                self.days.SelectRange()

    def OnSelectDays(self, event):
        print event.GetRightCol()

    def OnEnterWindow(self, event):
        font = event.GetEventObject().GetFont()
        font.SetUnderlined(True)
        event.GetEventObject().SetFont(font)
        event.GetEventObject().SetCursor(wx.StockCursor(wx.CURSOR_HAND))

    def OnLeaveWindow(self, event):
        font = event.GetEventObject().GetFont()
        font.SetUnderlined(False)
        event.GetEventObject().SetFont(font)
        event.GetEventObject().SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
        
    def SetDate(self):
        self.days.BeginBatch()
        date = wx.DateTime.Now()
        self.daystable.date = self.date

        date.SetDay(1)
        date.SetYear(self.date.GetYear())
        date.SetMonth(self.date.GetMonth())
        date.SetDay(self.date.GetDay())
 
        self.title.SetLabel(self.date.Format(wx.GetTranslation('%b, %Y')))
        
        firstWeekday = date.SetDay(1).GetWeekDay()
        lastDay = date.SetToLastMonthDay().GetDay()

        weeks = math.ceil(float(lastDay + firstWeekday) / 7)
        if weeks == 4 or ( weeks == 5 and firstWeekday ==0 ):
            firstWeek = 1
        else:
            firstWeek = 0
        self.firstCellofThisMonth = firstWeek * 7 + firstWeekday

        date.SetDay(1)
        date += wx.DateSpan_Days(-self.firstCellofThisMonth)
                
        self.daystable.days = []
        self.days.ClearSelection()
        for i in range(0, 42):
            d = wx.DateTime.Now()
            d.SetDay(1);
            d.SetYear(date.GetYear())
            d.SetMonth(date.GetMonth())
            d.SetDay(date.GetDay())
            
            self.daystable.days.append(d)
            r = i/7
            c = i%7
            if d.IsSameDate(wx.DateTime.Now()):
                self.days.SetCellBackgroundColour(r, c, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
                self.days.SetCellTextColour(r, c, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
            elif d.GetMonth() != self.date.GetMonth():
                self.days.SetCellTextColour(r, c, wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT))
                self.days.SetCellBackgroundColour(r, c, self.days.GetDefaultCellBackgroundColour())
            else:
                self.days.SetCellTextColour(r, c, wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT))
                self.days.SetCellBackgroundColour(r, c, self.days.GetDefaultCellBackgroundColour())
                self.lastCellofThisMonth = i
            if d.IsSameDate(self.date):
                self.days.SetGridCursor(r, c)
                self.currentCell = i
            date += wx.DateSpan_Days(1)

        self.daystable.UpdateWeeks()
#        self.cells[self.firstCellofThisMonth + self.date.GetDay() - 1].SetSelected(True)
#        self.Refresh()
        self.days.EndBatch()

    def ShowDetails(self):
        event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.idShowDetails)
        wx.PostEvent(self, event)
        
    def SelectMonth(self):
        self.days.beginRangeRow = self.firstCellofThisMonth / 7
        self.days.beginRangeCol = self.firstCellofThisMonth % 7
        self.days.endRangeRow = self.lastCellofThisMonth / 7
        self.days.endRangeCol = self.lastCellofThisMonth % 7
        self.days.SelectRange()
        
    def SelectWeek(self):
        r = self.currentCell / 7
        self.days.beginRangeRow, self.days.beginRangeCol = r, 0
        self.days.endRangeRow, self.days.endRangeCol = r, 6
        self.days.SelectRange()